package repository

import (
	"errors"
	"fmt"
	"invitation/internal/model"
	"invitation/internal/repository/cache"

	"gorm.io/gorm"
)

type GameIntroductionRepository interface {
	Create(gameInfoID uint, introduction string) error
	Update(gameInfoID uint, introduction string) error

	FindOneByGameInfoID(gameInfoID uint) (*model.GameIntroduction, error)

	FindListByGameInfoIDs(gameInfoIDs []uint) ([]model.GameIntroduction, error)
	Delete(gameInfoID uint) error
}

type gameIntroductionRepository struct{ *BaseRepository }

func newGameIntroductionRepository(db *gorm.DB) *gameIntroductionRepository {
	return &gameIntroductionRepository{
		BaseRepository: newBaseRepository(db),
	}
}
func (gir *gameIntroductionRepository) Create(gameInfoID uint, introduction string) error {
	gameIntroduction := &model.GameIntroduction{
		GameInfoID:   gameInfoID,
		Introduction: introduction,
	}
	return gir.GetDB().Create(gameIntroduction).Error
}
func (gir *gameIntroductionRepository) Update(gameInfoID uint, introduction string) error {
	// 1. 获取旧数据，用于判断记录是否存在以及后续可能的零值保留逻辑
	var oldGameIntroduction model.GameIntroduction
	if err := gir.GetDB().Where("game_info_id = ?", gameInfoID).First(&oldGameIntroduction).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return fmt.Errorf("game introduction with game_info_id %d not found, cannot update", gameInfoID)
		}
		return err // 返回其他数据库错误
	}

	// 2. 构建更新 Map
	updateData := make(map[string]interface{})

	// 3. 检查 Introduction 字段
	// 如果新值不为空字符串（零值），则进行更新
	if introduction != "" {
		updateData["introduction"] = introduction
	}
	// 如果 introduction 为 ""，则它不会被加入 updateData，GORM 会保留旧值。

	// 4. 执行更新
	// 如果 updateData 为空，说明没有提供任何有效更新字段，则无需执行数据库操作
	if len(updateData) == 0 {
		return nil // 或者返回一个自定义错误，如 errors.New("no fields to update")
	}

	// 使用 Updates 方法，它会自动处理 UpdatedAt
	return gir.GetDB().Model(&oldGameIntroduction).Updates(updateData).Error
}

func (gir *gameIntroductionRepository) FindOneByGameInfoID(gameInfoID uint) (*model.GameIntroduction, error) {
	var gameIntroduction model.GameIntroduction
	err := gir.GetDB().Where("game_info_id = ?", gameInfoID).First(&gameIntroduction).Error
	if err != nil {
		return nil, err
	}
	return &gameIntroduction, nil
}
func (gir *gameIntroductionRepository) FindListByGameInfoIDs(gameInfoIDs []uint) ([]model.GameIntroduction, error) {
	var gameIntroductionList []model.GameIntroduction
	err := gir.GetDB().Where("game_info_id IN (?)", gameInfoIDs).Find(&gameIntroductionList).Error
	if err != nil {
		return nil, err
	}
	return gameIntroductionList, nil
}
func (gir *gameIntroductionRepository) Delete(gameInfoID uint) error {
	return gir.GetDB().Delete(&model.GameIntroduction{}, gameInfoID).Error
}

type cachedGameIntrouctionRepository struct{ *BaseCachedRepository }

var introductionIDKey = "introduction_id"

func newCachedGameIntroudctionRepository(db *gorm.DB, cache *cache.LRU, repoName string) *cachedGameIntrouctionRepository {
	repo := newGameIntroductionRepository(db)
	return &cachedGameIntrouctionRepository{
		BaseCachedRepository: newBaseCachedRepository(repo, cache, repoName),
	}
}

func (cgr *cachedGameIntrouctionRepository) BaseRepo() *gameIntroductionRepository {
	return cgr.GetBaseRepo().(*gameIntroductionRepository)
}
func (cgr *cachedGameIntrouctionRepository) Create(gameInfoID uint, introduction string) error {
	cgr.mutex.Lock()
	defer cgr.mutex.Unlock()
	if cgr.GetCache() == nil {
		return cgr.BaseRepo().Create(gameInfoID, introduction)
	}
	cacheKey := cgr.GenerateCacheKey(introductionIDKey, gameInfoID)
	cgr.GetCache().Remove(cacheKey)
	return cgr.BaseRepo().Create(gameInfoID, introduction)
}
func (cgr *cachedGameIntrouctionRepository) Update(gameInfoID uint, introduction string) error {
	cgr.mutex.Lock()
	defer cgr.mutex.Unlock()

	// 调用 BaseRepo 的 Update 方法，它现在包含了零值保留逻辑
	err := cgr.BaseRepo().Update(gameInfoID, introduction)
	if err != nil {
		return err
	}

	if cgr.GetCache() == nil {
		return nil
	}

	// 无论是否真的更新了数据库，只要 BaseRepo.Update 没有报错，
	// 我们就认为这个 ID 对应的缓存可能已失效，因此移除它。
	// 下次查询时会从数据库重新加载。
	cacheKey := cgr.GenerateCacheKey(introductionIDKey, gameInfoID)
	cgr.GetCache().Remove(cacheKey)

	return nil
}
func (cgr *cachedGameIntrouctionRepository) FindOneByGameInfoID(gameInfoID uint) (*model.GameIntroduction, error) {
	cgr.mutex.Lock()
	defer cgr.mutex.Unlock()
	if cgr.GetCache() == nil {
		return cgr.BaseRepo().FindOneByGameInfoID(gameInfoID)
	}
	cacheKey := cgr.GenerateCacheKey(introductionIDKey, gameInfoID)
	if value, ok := cgr.GetCache().Get(cacheKey); ok {
		return value.(*model.GameIntroduction), nil
	}
	gameIntroduction, err := cgr.BaseRepo().FindOneByGameInfoID(gameInfoID)
	if err != nil {
		return nil, err
	}
	cgr.GetCache().Add(cacheKey, gameIntroduction)
	return gameIntroduction, nil
}

// 联查不缓存
func (cgr *cachedGameIntrouctionRepository) FindListByGameInfoIDs(gameInfoIDs []uint) ([]model.GameIntroduction, error) {
	return cgr.BaseRepo().FindListByGameInfoIDs(gameInfoIDs)
}
func (cgr *cachedGameIntrouctionRepository) Delete(gameInfoID uint) error {
	cgr.mutex.Lock()
	defer cgr.mutex.Unlock()
	if cgr.GetCache() == nil {
		return cgr.BaseRepo().Delete(gameInfoID)
	}
	cacheKey := cgr.GenerateCacheKey(introductionIDKey, gameInfoID)
	cgr.GetCache().Remove(cacheKey)
	return cgr.BaseRepo().Delete(gameInfoID)
}
func NewGameIntroudctionRepositoryWithCache(db *gorm.DB, cache *cache.LRU, repoName string) Repository {
	return newCachedGameIntroudctionRepository(db, cache, repoName)
}
